package commons.base.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

/**
 * Deflate压缩解压缩工具类
 * @author yuan<cihang.yuan@happyelements.com>
 *
 */
public class DeflateUtil {

	/**
	 * Deflate压缩
	 * @param data
	 * @return
	 */
	public static byte[] compress(byte[] data){
		return compress(data, 0, data.length);
	}
	/**
	 * Deflate压缩
	 * @param data
	 * @param offset
	 * @param len
	 * @return
	 */
	public static byte[] compress(byte[] data, int offset, int len){
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		compress(data, offset, len, bos);
		return bos.toByteArray();
	}
	
	/**
	 * Deflate压缩
	 * @param data
	 * @param offset
	 * @param len
	 * @param bos
	 */
	public static void compress(byte[] data, int offset, int len, ByteArrayOutputStream bos){
		Deflater compresser = new Deflater(1, true);
		compresser.setInput(data, offset, len);
		compresser.finish();
		byte[] buf = new byte[512];
		int length = compresser.deflate(buf);
		while(length > 0) {
			bos.write(buf, 0, length);
			length = compresser.deflate(buf);
		}
		compresser.end();
	}
	
	/**
	 * 流压缩，需要外部来关闭输入流和输出流
	 * @param is
	 * @param os
	 */
	public static void compress(InputStream is, OutputStream os) {
		Deflater deflater = null;
		try {
			deflater = new Deflater(1, true);
			BufferedInputStream bis = wrapperInputStream(is);
			DeflaterOutputStream gos = new DeflaterOutputStream(wrapperOutputStream(os), deflater);
			
			int data = -1;
			while((data = bis.read()) != -1){
				gos.write(data);
			}
			gos.finish();
			gos.flush();
		}catch (IOException e) {
			throw new RuntimeException(e.getMessage(), e);
		} finally{
			if(deflater != null) deflater.end();
		}
	}
	
	private static BufferedInputStream wrapperInputStream(InputStream is){
		if(is instanceof BufferedInputStream){
			return (BufferedInputStream)is;
		}
		
		return new BufferedInputStream(is);
	}
	private static BufferedOutputStream wrapperOutputStream(OutputStream os){
		if(os instanceof BufferedOutputStream){
			return (BufferedOutputStream)os;
		}
		
		return new BufferedOutputStream(os);
	}
	
	/**
	 * 流解压缩，需要外部来关闭输入流和输出流
	 * @param is
	 * @param os
	 * @throws IOException
	 */
	public static void uncompress(InputStream is, OutputStream os) {
		Inflater inflater = null;
		try {
			inflater = new Inflater(true);
			InflaterInputStream gis = new InflaterInputStream(wrapperInputStream(is), inflater);
			BufferedOutputStream bos = wrapperOutputStream(os);

			int data = -1;
			while ((data = gis.read()) != -1) {
				bos.write(data);
			}
		}catch (IOException e) {
			throw new RuntimeException(e.getMessage(), e);
		} finally {
			if(inflater != null) inflater.end();
		}

	}
	
	/**
	 * Deflate解压缩
	 * @param data
	 * @return
	 */
	public static byte[] uncompress(byte[] data){
		return uncompress(data, 0, data.length);
	}
	/**
	 * Deflate解压缩
	 * @param data
	 * @param offset
	 * @param len
	 * @return
	 */
	public static byte[] uncompress(byte[] data, int offset, int len){
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		uncompress(data, offset, len, bos);
		return bos.toByteArray();
	}
	
	/**
	 * Deflate解压缩
	 * @param data
	 * @param offset
	 * @param len
	 * @param bos
	 */
	public static void uncompress(byte[] data, int offset, int len, ByteArrayOutputStream bos){
		Inflater decompresser = new Inflater(true);
		decompresser.setInput(data,  offset, len);
		byte[] buf = new byte[512];
		try {
			int length = decompresser.inflate(buf);
			while(length > 0) {
				bos.write(buf, 0, length);
				length = decompresser.inflate(buf);
			}
		} catch (DataFormatException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
		decompresser.end();
	}

}
